package com.test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

//单线程的Reactor
class Reactor implements Runnable {
	final Selector selector;
	final ServerSocketChannel serverSocket;

	Reactor(int port) throws IOException {
		selector = Selector.open();
		serverSocket = ServerSocketChannel.open();
		serverSocket.socket().bind(new InetSocketAddress(port));
		serverSocket.configureBlocking(false);
		SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
		sk.attach(new Acceptor());// sk附加任意对象
	}

	/*
	 * Alternatively, use explicit SPI provider: SelectorProvider p =
	 * SelectorProvider.provider(); selector = p.openSelector(); serverSocket =
	 * p.openServerSocketChannel();
	 */
 
	public void run() { // normally in a new Thread
		try {
			while (!Thread.interrupted()) {
				selector.select();
				Set selected = selector.selectedKeys();
				Iterator it = selected.iterator();
				while (it.hasNext())
					dispatch((SelectionKey)(it.next()));  //Reactor分发key
				selected.clear();//处理完的key事件一定要清除掉
			}
		} catch (IOException ex) { }
	}

	void dispatch(SelectionKey k) { // Reactor分发key
		Runnable r = (Runnable) (k.attachment()); // 获取之前附加的Acceptor对象
		if (r != null)
			r.run();// 调用Acceptor的run方法
	}

	class Acceptor implements Runnable {  
		public void run() {
			try {
				SocketChannel c = serverSocket.accept();
				if (c != null)
					new Handler(selector, c);
			} catch (IOException ex) {
			}
		}
	}

	final class Handler implements Runnable {
		final SocketChannel socket;
		final SelectionKey sk;
		ByteBuffer input = ByteBuffer.allocate(Integer.MIN_VALUE);
		ByteBuffer output = ByteBuffer.allocate(Integer.MAX_VALUE);
		static final int READING = 0, SENDING = 1;
		int state = READING;

		Handler(Selector sel, SocketChannel c) throws IOException {
			socket = c;
			c.configureBlocking(false);
			// Optionally try first read now
			sk = socket.register(sel, 0);
			sk.attach(this);
			sk.interestOps(SelectionKey.OP_READ);// 注册读事件
			sel.wakeup();// 如果有之前的select()方法阻塞了，就要他立即返回
		}

		boolean inputIsComplete() {
			return false; }
		boolean outputIsComplete() {
			return false; }
		void process() { }

		public void run() {
			try {
				if (state == READING)
					read();
				else if (state == SENDING)
					send();
			} catch (IOException ex) { }
		}

		void read() throws IOException {
			socket.read(input);
			if (inputIsComplete()) {
				process();
				state = SENDING;
				// Normally also do first write now
				sk.attach(new Sender());
				sk.interestOps(SelectionKey.OP_WRITE);
				sk.selector().wakeup();
			}
		}

		void send() throws IOException {
			socket.write(output);
			if (outputIsComplete())
				sk.cancel();
		}
		
		class Sender implements Runnable {
			public void run() {  
				try {
					socket.write(output);
				} catch (IOException e) {
					e.printStackTrace();
				}
				if (outputIsComplete())
					sk.cancel();
			}
		}
	}

	
}